package com.siashan.toolkit.api.security;

import cn.hutool.crypto.CryptoException;
import com.siashan.toolkit.api.security.dto.RequestDto;
import com.siashan.toolkit.api.security.properties.RestCryptoProperties;
import com.siashan.toolkit.api.security.util.RequestUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;

import java.io.IOException;
import java.io.InputStream;

/**
 * 自定义HttpInputMessage
 *
 * @author siashan
 * @version V1.0.1
 **/
public class RestCryptoHttpInputMessage implements HttpInputMessage {
    /**
     * 请求头
     */
    private HttpHeaders headers;
    /**
     * 请求体
     */
    private InputStream body;

    /**
     * 接口请求参数
     */
    private RequestDto requestDto;

    public RestCryptoHttpInputMessage(HttpInputMessage httpInputMessage, RestCryptoProperties restCryptoProperties) throws Exception {
        this.headers = httpInputMessage.getHeaders();
        // 解密操作
        decryptBody(httpInputMessage.getBody(), restCryptoProperties);
    }


    /**
     * 解析请求报文并传递到下一层
     *
     * @param body                 请求体
     * @param restCryptoProperties 配置文件
     * @throws Exception
     */
    private void decryptBody(InputStream body, RestCryptoProperties restCryptoProperties) throws Exception {
        this.body = RequestUtil.decryptBody(parseRequestDto(body, restCryptoProperties), restCryptoProperties);
    }


    /**
     * 解析RequestDto对象
     *
     * @param body                 请求体
     * @param restCryptoProperties 配置信息
     * @return RequestDto对象
     * @throws IOException
     */
    private RequestDto parseRequestDto(InputStream body, RestCryptoProperties restCryptoProperties) throws IOException {
        String storepath = restCryptoProperties.getSign().getStorepath();
        RequestDto requestDto = null;
        if (CryptoConst.STORE_PATH_BODY.equals(storepath)) {
            // 签名字段存储在Body中
            requestDto = RequestUtil.getRequestDto(body);
        } else {
            // 签名字段存储在Header中
            requestDto = RequestUtil.getRequestDto(body, headers);
        }
        if (null == requestDto) {
            throw new CryptoException("请求参数不合法，请检查后重试");
        }
        this.requestDto = requestDto;
        return requestDto;
    }

    @Override
    public InputStream getBody() {
        return body;
    }

    @Override
    public HttpHeaders getHeaders() {
        return headers;
    }


    public RequestDto getRequestDto() {
        return requestDto;
    }
}
